//
//  ArrayExtensions.swift
//  SwiftUI
//
//  Created by lvfeijun on 2021/12/27.
//  Copyright © 2021 lvfeijun. All rights reserved.
//

import Foundation
import UIKit
import HandyJSON
import Accelerate

/// 两个数组是否相等
public func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool{
    switch (lhs,rhs){
        case let(lhs?,rhs?):
            return lhs == rhs
        
    case (.none, .none):
        return true
        
    default:
        return false
    }

    
}

extension Array {
    
    /// EZSE: 检查数组是否包含至少 1 个与给定元素类型相同的项目
    public func containsType<T>(of element: T) -> Bool {
        let elementType = type(of: element)
        return contains { type(of: $0) == elementType}
    }
    
    /// EZSE: 将数组分解为具有第一个元素和其余元素的元组
    public func decompose() ->(head: Iterator.Element, tail:SubSequence)?{
        return (count>0) ? (self[0], self[1..<count]):nil
    }
    
    /// EZSE: 使用其索引迭代数组的每个元素。 （索引，元素）
    public func forEachEnumerated(_ body: @escaping (_ offset: Int, _ element: Element) -> Void){
        enumerated().forEach(body)
    }
    
    /// EZSE:
    public func get(at index: Int) -> Element? {
        guard index>=0 && index < count else { return nil}
        return self[index]
    }
    
    /// EZSE: 将对象添加到数组中。
    public mutating func insertFirst(_ newElement: Element){
        insert(newElement, at: 0)
    }
    
    /// EZSE: 从数组中返回一个随机元素。
    public func random() -> Element? {
        guard count > 0 else { return nil }
        let index = Int(arc4random_uniform(UInt32(count)))
        return self[index]
    }
    
    /// EZSE: 反转给定的索引。 例如：reverseIndex(2) 将是 2 到最后
    public func reverseIndex(_ index: Int) -> Int? {
        guard index >= 0 && index < count else { return nil }
        return Swift.max(count - 1 - index, 0)
    }
    
    /// EZSE: 使用 Fisher-Yates-Durstenfeld 算法就地打乱数组。
    public mutating func shuffle() {
        guard count > 1 else { return }
        var j:Int
        for i in 0..<(count-2) {
            j = Int(arc4random_uniform(UInt32(count - i)))
            if i != i+j { self.swapAt(i, i+j) }
        }
    }
    
    /// EZSE: 使用 Fisher-Yates-Durstenfeld 算法打乱复制的数组，返回打乱的数组。
    public func shuffled() -> Array {
        var result = self
        result.shuffle()
        return result
    }
    
    /// EZSE: 返回以给定数字作为最大元素数的数组。
    public func takeMax(_ n: Int) -> Array {
        return Array(self[0..<Swift.max(0, Swift.min(n, count))])
    }
    
    /// EZSE:检查 test 是否对 self 中的所有元素返回 true
    public func testAll(_ body: @escaping (Element) -> Bool) -> Bool {
        return !contains { !body($0) }
    }
    
    /// EZSE:检查数组中的所有元素是真还是假
    public func testAll(is condition: Bool) -> Bool {
        return testAll{ ($0 as? Bool) ?? !condition == condition }
    }
}

extension Array where Element: Equatable {
    /// EZSE:检查主数组是否包含参数数组
    public func contains(_ array: [Element]) -> Bool {
        return testAll { self.firstIndex(of: $0) ?? -1 >= 0 }
    }
    
    /// EZSE: 检查 self 是否包含项目列表。
    public func contains(_ element: Element...) -> Bool {
        return element.testAll { self.firstIndex(of: $0) ?? -1 >= 0}
    }
    
    /// EZSE:返回对象的索引
    public func indexes(of element: Element) -> [Int] {
        return enumerated().compactMap { ($0.element == element) ? $0.offset : nil}
    }
    
    /// EZSE: 返回对象的最后一个索引
    public func lastIndex(of element: Element) ->Int? {
        return indexes(of: element).last
    }
    
    /// EZSE: 移除第一个给定的对象
    public mutating func removeFirst(_ element: Element) {
        guard let index = firstIndex(of: element) else { return }
        self.remove(at: index)
    }
    
    /// EZSE: 删除所有出现的给定对象，至少需要一个条目。
    public mutating func removeAll(_ firstElement: Element?, _ elements: Element...) {
        var removeAllArr = [Element]()
        
        if let firstElementVal = firstElement {
            removeAllArr.append(firstElementVal)
        }
        
        elements.forEach({element in removeAllArr.append(element)})
        
        removeAll(removeAllArr)
    }
    
    /// EZSE:删除所有出现的给定对象
    public mutating func removeAll(_ elements: [Element]) {
        self = filter { !elements.contains($0) }
    }
    
    /// EZSE: self 和输入数组的差异。
    public func difference(_ values: [Element]...) -> [Element] {
        var result = [Element]()
        elements: for element in self {
            for value in values {
                // 如果一个值在 self 和值数组之一中
                // 跳到外循环的下一次迭代
                if value.contains(element) {
                    continue elements
                }
            }
            // 元素，它只在 self 中
            result.append(element)
        }
        return result
    }
    
    /// EZSE: self 和输入数组的交集。
    public func intersection(_ values: [Element]...) -> Array {
        var result = self
        var intersetction = Array()
        
        for (i, value) in values.enumerated() {
            // 交集是通过在每个循环中相交一对来计算的：
            // self n values[0], (self n values[0]) n values[1], ...
            if i>0 {
                result = intersetction
                intersetction = Array()
            }
            
            // 找到公共元素并将它们保存在第一个集合中
            // 在下一个循环中相交
            value.forEach { (item: Element) -> Void in
                if result.contains(item){
                    intersetction.append(item)
                }
            }
        }
        return intersetction
    }
    
    /// EZSE:self 和输入数组的联合。
    public func union(_ values: [Element]...) -> Array {
        var result = self
        for array in values {
            for value in array {
                if !result.contains(value) {
                    result.append(value)
                }
            }
        }
        return result
    }
    
    /// EZSE: 返回由数组中唯一元素组成的数组
    public func unique() -> Array {
        return reduce([]) { $0.contains($1) ? $0 : $0 + [$1] }
    }
    
    
}


